﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;

namespace Missbot.Common
{
    /// <summary>
    /// DI服务
    /// </summary>
    public class AutofacSvc
    {
        /// <summary>
        /// 容器
        /// </summary>
        public static IContainer Container;

        public static List<Assembly> AllAssemblies;

        /// <summary>
        /// 类型解析
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Resolve<T>()
        {
            return Container.Resolve<T>();
        }

        /// <summary>
        /// 类型解析
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object Resolve(Type type)
        {
            return Container.Resolve(type);
        }

        /// <summary>
        /// 按程序集批量注册服务
        /// </summary>
        /// <param name="builder"></param>
        public static void RegisterAutofac(ContainerBuilder builder)
        {
            var singletonBaseType = typeof(ISingleton);
            builder.RegisterAssemblyTypes(AllAssemblies.ToArray())
                   .Where(type => singletonBaseType.IsAssignableFrom(type) && !type.IsAbstract)
                   .AsSelf()
                   .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
                   .SingleInstance();

            var transientBaseType = typeof(ITransient);
            builder.RegisterAssemblyTypes(AllAssemblies.ToArray())
                   .Where(type => transientBaseType.IsAssignableFrom(type) && !type.IsAbstract)
                   .AsSelf()
                   .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
                   .InstancePerDependency();

            Container = builder.Build();
        }

        /// <summary>
        /// 初始化数据托管实例
        /// </summary>
        public static void RegisterDataRefresher()
        {
            var datamgrs = LoadAllInstanceFromInterface<IDataMgr>();

            foreach (var datamgr in datamgrs)
            {
                datamgr.RefreshData();
                Container.Resolve<DataRefreshSvc>().Register(datamgr);
            }
        }

        /// <summary>
        /// 加载指定父类的所有子类的实例
        /// </summary>
        /// <param name="assembly">指定程序集（默认为当前程序集）</param>
        /// <typeparam name="T">父类类型</typeparam>
        /// <returns>所有子类的实例列表</returns>
        public static List<T> LoadAllInstanceFromClass<T>(Assembly assembly) where T : class
        {
            assembly ??= Assembly.GetAssembly(typeof(T));
            var list = assembly?.GetTypes()
                                .Where(type => type.IsSubclassOf(typeof(T)) && !type.IsAbstract && type.FullName != null)
                                .Select(type => Container.IsRegistered(type)
                                                    ? Container.Resolve(type) as T
                                                    : assembly.CreateInstance(type.FullName) as T);

            return list?.ToList();
        }

        /// <summary>
        /// 加载指定父类的所有子类的实例
        /// </summary>
        /// <typeparam name="T">父类类型</typeparam>
        /// <returns>所有子类的实例列表</returns>
        public static List<T> LoadAllInstanceFromClass<T>() where T : class
        {
            return AllAssemblies.SelectMany(p => p.GetTypes().Where(type => type.IsSubclassOf(typeof(T)) && !type.IsAbstract))
                                .Where(type => Container.IsRegistered(type))
                                .Select(type => Resolve(type) as T)
                                .Where(d => d != null)
                                .ToList();
        }

        /// <summary>
        /// 加载指定接口的所有子类的实例
        /// </summary>
        /// <param name="assembly">指定程序集（默认为当前程序集）</param>
        /// <typeparam name="T">接口类型</typeparam>
        /// <returns>所有子类的实例列表</returns>
        public static List<T> LoadAllInstanceFromInterface<T>(Assembly assembly) where T : class
        {
            assembly ??= Assembly.GetAssembly(typeof(T));
            var list = assembly?.GetTypes()
                                .Where(type => typeof(T).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract && type.FullName != null)
                                .Select(type => Container.IsRegistered(type)
                                                    ? Container.Resolve(type) as T
                                                    : assembly.CreateInstance(type.FullName) as T);

            return list?.ToList();
        }

        /// <summary>
        /// 加载指定接口的所有子类的实例
        /// </summary>
        /// <typeparam name="T">接口类型</typeparam>
        /// <returns>所有子类的实例列表</returns>
        public static List<T> LoadAllInstanceFromInterface<T>() where T : class
        {
            return AllAssemblies.SelectMany(p => p.GetTypes().Where(type => typeof(T).IsAssignableFrom(type) && !type.IsAbstract))
                                .Select(type => Container.IsRegistered(type)
                                                    ? Container.Resolve(type) as T
                                                    : typeof(T).Assembly.CreateInstance(type.FullName ?? string.Empty) as T)
                                .Where(d => d != null)
                                .ToList();
        }
    }
}